package com.mybatis.lo.executor;

import com.mybatis.lo.cache.PerpetualCache;
import com.mybatis.lo.config.Configuration;
import com.mybatis.lo.config.MappedStatement;
import com.mybatis.lo.mapping.BoundSql;

import java.util.List;

/**
 * 基础执行器，实现缓存（一级缓存），查询实际动作由子类实现。
 * 通过{@link PerpetualCache } 简单实现一级缓存
 * @author zhangbh
 * 2023-06-19 07:43
 **/
public abstract class BaseExecutor implements Executor {

    private final PerpetualCache localCache = new PerpetualCache();

    @Override
    public <T> List<T> queryList(MappedStatement statement, Configuration configuration, Object param) {
        // 获取到绑定sql
        BoundSql boundSql = statement.getBoundSql(param);
        // 获取到缓存key
        String cacheKey = getCacheKey(boundSql, param);
        Object data = localCache.get(cacheKey);
        if (data != null) {
            return (List<T>) data;
        }
        List<T> result = queryFromDatabases(statement, configuration, param);
        // 如果查询不为空，则放入缓存
        if (result != null) {
            System.out.println("查询数据加入一级缓存,key=" + cacheKey);
            localCache.put(cacheKey, result);
        }
        return result;
    }

    /**
     * 简单方法计算一个根据入参固定的缓存key
     * @param boundSql sql
     * @param param 参数
     * @return 缓存key
     */
    private String getCacheKey(BoundSql boundSql, Object param) {
        String sql = boundSql.getSql();
        // 可优化 简单的把sql和入参的hashCode
        return sql + param.hashCode();
    }

    /**
     * 从数据库中查询数据
     * @param statement 预备配置
     * @param configuration 全局配置
     * @param param 入参
     * @param <T> 类型
     * @return 数据
     */
    protected abstract <T> List<T> queryFromDatabases(MappedStatement statement, Configuration configuration, Object param);
}
